home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / xvisrc.zip / MISCCMDS.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  11KB  |  521 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)misccmds.c    2.2 (Chris & John Downey) 8/28/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     misccmds.c
  14. * module function:
  15.     Miscellaneous functions.
  16.  
  17.     This module will probably get hacked later and split
  18.     up more sensibly.
  19. * history:
  20.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  21.     Originally by Tim Thompson (twitch!tjt)
  22.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  23.     Heavily modified by Chris & John Downey
  24.  
  25. ***/
  26.  
  27. #include "xvi.h"
  28.  
  29. /*
  30.  * Add a blank line above or below the current line.
  31.  * Returns TRUE for success, FALSE for failure to get memory.
  32.  *
  33.  * The single boolean parameter tells us whether to split the
  34.  * current line at the cursor position, or just to open a new
  35.  * line leaving the current one intact.
  36.  */
  37. bool_t
  38. openfwd(split_line)
  39. bool_t    split_line;
  40. {
  41.     Line        *l;        /* pointer to newly allocated line */
  42.     register Posn    *oldposn;
  43.     register Line    *oldline;
  44.     register char    *otext;
  45.  
  46.     oldposn = curwin->w_cursor;
  47.     oldline = oldposn->p_line;
  48.     otext = oldline->l_text;
  49.  
  50.     /*
  51.      * First find space for new line.
  52.      *
  53.      * By asking for as much space as the prior line had we make sure
  54.      * that we'll have enough space for any auto-indenting.
  55.      */
  56.     l = newline(strlen(otext) + SLOP);
  57.     if (l == NULL)
  58.     return(FALSE);
  59.  
  60.     /*
  61.      * Link the new line into the list.
  62.      */
  63.     repllines(curwin, oldline->l_next, 0L, l);
  64.  
  65.     /*
  66.      * Do auto-indent.
  67.      */
  68.     if (Pb(P_autoindent)) {
  69.     *l->l_text = '\0';
  70.     indentchars = set_indent(l, get_indent(oldline));
  71.     } else {
  72.     indentchars = 0;
  73.     }
  74.  
  75.     /*
  76.      * If we're in insert mode, we need to move the remainder of the
  77.      * current line onto the new line. Otherwise the new line is left
  78.      * blank.
  79.      */
  80.     if (split_line) {
  81.     char    *s;
  82.  
  83.     s = otext + oldposn->p_index;
  84.  
  85.     replchars(curwin, l, indentchars, 0, s);
  86.     replchars(curwin, oldline, oldposn->p_index, strlen(s), "");
  87.     }
  88.  
  89.     /*
  90.      * Move cursor to the new line.
  91.      */
  92.     move_cursor(curwin, l, indentchars);
  93.     move_window_to_cursor(curwin);
  94.     cursupdate(curwin);
  95.     update_buffer(curbuf);
  96.  
  97.     return(TRUE);
  98. }
  99.  
  100. /*
  101.  * Add a blank line above the current line.
  102.  * Returns TRUE for success, FALSE for failure to get memory.
  103.  */
  104. bool_t
  105. openbwd()
  106. {
  107.     Line        *l;
  108.     register Line    *oldline;
  109.     register char    *otext;
  110.  
  111.     oldline = curwin->w_cursor->p_line;
  112.     otext = oldline->l_text;
  113.  
  114.     /*
  115.      * First find space for new line.
  116.      */
  117.     l = newline(strlen(otext) + SLOP);
  118.     if (l == NULL)
  119.     return(FALSE);
  120.  
  121.     /*
  122.      * Link the new line into the list.
  123.      */
  124.     repllines(curwin, oldline, 0L, l);
  125.  
  126.     /*
  127.      * Do auto-indent.
  128.      */
  129.     if (Pb(P_autoindent)) {
  130.     *l->l_text = '\0';
  131.     indentchars = set_indent(l, get_indent(oldline));
  132.     } else {
  133.     indentchars = 0;
  134.     }
  135.  
  136.     /*
  137.      * Ensure the cursor is pointing at the right line.
  138.      */
  139.     move_cursor(curwin, l, indentchars);
  140.     move_window_to_cursor(curwin);
  141.     cursupdate(curwin);
  142.     update_buffer(curbuf);
  143.  
  144.     return(TRUE);
  145. }
  146.  
  147. /*
  148.  * Count the number of lines between the two given lines.
  149.  * If the two given lines are the same, the return value
  150.  * is 1, not 0; i.e. the count is inclusive.
  151.  *
  152.  * Note that this function has been changed to give the
  153.  * correct number of lines, even if they are ordered wrongly.
  154.  * This change is backwards-compatible with the old version.
  155.  */
  156. long
  157. cntllines(pbegin, pend)
  158. Line        *pbegin;
  159. register Line    *pend;
  160. {
  161.     register Line    *lp;
  162.     register long    lnum;
  163.     bool_t        swapped = FALSE;
  164.  
  165.     /*
  166.      * Ensure correct ordering.
  167.      */
  168.     if (later(pbegin, pend)) {
  169.     lp = pbegin;
  170.     pbegin = pend;
  171.     pend = lp;
  172.     swapped = TRUE;
  173.     }
  174.  
  175.     for (lnum = 1, lp = pbegin; lp != pend; lp = lp->l_next) {
  176.     lnum++;
  177.     }
  178.  
  179.     if (swapped)
  180.     lnum = - lnum;
  181.  
  182.     return(lnum);
  183. }
  184.  
  185. /*
  186.  * plines(lp) - return the number of physical screen lines taken by line 'lp'.
  187.  */
  188. long
  189. plines(win, lp)
  190. Xviwin    *win;
  191. Line    *lp;
  192. {
  193.     register long    col;
  194.     register char    *s;
  195.  
  196.     s = lp->l_text;
  197.  
  198.     if (*s == '\0')        /* empty line */
  199.     return(1);
  200.  
  201.     /*
  202.      * If list mode is on, then the '$' at the end of
  203.      * the line takes up one extra column.
  204.      */
  205.     col = Pb(P_list) ? 1 : 0;
  206.  
  207.     if (Pb(P_number)) {
  208.     col += NUM_SIZE;
  209.     }
  210.  
  211.     for ( ; *s != '\0'; s++) {
  212.     col += vischar(*s, (char **) NULL, (int) col);
  213.     }
  214.  
  215.     {
  216.     register int    row;
  217.     register int    columns;
  218.  
  219.     columns = win->w_ncols;
  220.     for (row = 1; col > columns; ) {
  221.         row++;
  222.         col -= columns;
  223.     }
  224.     return row;
  225.     }
  226. }
  227.  
  228. /*
  229.  * Count the number of physical lines between the two given lines.
  230.  *
  231.  * This routine is like cntllines(), except that:
  232.  *    it counts physical rather than logical lines
  233.  *    it always returns the absolute number of physical lines
  234.  *    it is non-inclusive
  235.  *    if the physical line count for a group of lines is greater
  236.  *    than or equal to rows * 2, we just return rows * 2; we assume
  237.  *    the caller isn't interested in the exact number.
  238.  */
  239. long
  240. cntplines(win, pbegin, pend)
  241. Xviwin        *win;
  242. Line        *pbegin;
  243. register Line    *pend;
  244. {
  245.     register Line    *lp;
  246.     register long    physlines;
  247.     unsigned        toomuch;
  248.  
  249.     /*
  250.      * Ensure correct ordering.
  251.      */
  252.     if (later(pbegin, pend)) {
  253.     lp = pbegin;
  254.     pbegin = pend;
  255.     pend = lp;
  256.     }
  257.  
  258.     toomuch = win->w_nrows * 2;
  259.     for (physlines = 0, lp = pbegin; lp != pend; lp = lp->l_next) {
  260.     physlines += plines(win, lp);
  261.     if (physlines >= toomuch)
  262.         break;
  263.     }
  264.  
  265.     return(physlines);
  266. }
  267.  
  268. /*
  269.  * gotoline(buffer, n) - return a pointer to line 'n' in the given buffer
  270.  *
  271.  * Returns the first line of the file if n is 0.
  272.  * Returns the last line of the file if n is beyond the end of the file.
  273.  */
  274. Line *
  275. gotoline(b, n)
  276. Buffer            *b;
  277. register unsigned long    n;
  278. {
  279.     if (n == 0) {
  280.     return(b->b_file);
  281.     } else {
  282.     register Line    *lp;
  283.  
  284.     for (lp = b->b_file; --n > 0 && lp->l_next != b->b_lastline;
  285.                             lp = lp->l_next) {
  286.         ;
  287.     }
  288.     return(lp);
  289.     }
  290. }
  291.  
  292. int
  293. get_indent(lp)
  294. register Line    *lp;
  295. {
  296.     register char   *text;
  297.     register int    indent;
  298.     register int    ts = Pn(P_tabstop);    /* synonym for efficiency */
  299.  
  300.     if (lp == NULL || (text = lp->l_text) == NULL) {
  301.     show_error(curwin, "Internal error: get_indent(NULL)");
  302.     return 0;
  303.     }
  304.  
  305.     for (indent = 0; *text != '\0' && (*text == ' ' || *text == '\t');
  306.                                     text++) {
  307.     indent += *text == ' ' ? 1 : ts - indent % ts;
  308.     }
  309.     return indent;
  310. }
  311.  
  312. /*
  313.  * Set number of columns of leading whitespace on line, regardless of
  314.  * what was there before, & return number of characters (not columns)
  315.  * used.
  316.  */
  317. int
  318. set_indent(lp, indent)
  319. Line        *lp;
  320. register int    indent;
  321. {
  322.     register char    *cp;        /* temp char pointer for loops */
  323.     register int    ntabs;        /* number of tabs to use */
  324.     unsigned        nnew;        /* no of chars used in old line */
  325.     unsigned        nold;        /* no of chars used in new version */
  326.     char        *newstr;    /* allocated string for new indent */
  327.  
  328.     if (lp == NULL || lp->l_text == NULL) {
  329.     show_error(curwin, "Internal error: set_indent(0)");
  330.     return(0);
  331.     }
  332.  
  333.     /*
  334.      * Find out how many tabs we need, & how many spaces.
  335.      */
  336.     for (ntabs = 0; indent >= Pn(P_tabstop); ntabs++)
  337.     indent -= Pn(P_tabstop);
  338.  
  339.     /*
  340.      * Find out how many characters were used for initial
  341.      * whitespace in the current (old) line.
  342.      */
  343.     for (cp = lp->l_text; *cp == ' ' || *cp == '\t'; cp++) {
  344.     ;
  345.     }
  346.     nold = cp - lp->l_text;
  347.  
  348.     /*
  349.      * "nnew" is the number of characters we will use
  350.      * for indentation in the new version of the line.
  351.      */
  352.     nnew = ntabs + indent;
  353.  
  354.     /*
  355.      * Get some space, and place into it the string of tabs
  356.      * and spaces which will form the new indentation.
  357.      * If no space available, return nold as we have not
  358.      * changed the line; this is the correct action.
  359.      */
  360.     newstr = alloc((unsigned) nnew + 1);
  361.     if (newstr == NULL)
  362.     return(nold);
  363.  
  364.     cp = newstr;
  365.     while (ntabs-- > 0)
  366.     *cp++ = '\t';
  367.     while (indent-- > 0)
  368.     *cp++ = ' ';
  369.     *cp = '\0';
  370.  
  371.     /*
  372.      * Finally, replace the old with the new.
  373.      */
  374.     replchars(curwin, lp, 0, (int) nold, newstr);